package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.config.VodProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.user.UserSubscribe;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.*;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private VodProperties vodProperties;

    @Autowired
    private VodService vodService;

    @Autowired
    private TrackStatMapper trackStatMapper;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private TrackInfoServiceImpl self; // 自我注入

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Override
    public Map<String, Object> uploadTrack(MultipartFile file) {
        return vodService.uploadTrack(file);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        // 1. 保存声音信息到track_info
        Long userId = AuthContextHolder.getUserId();
        TrackInfo trackInfo = new TrackInfo();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        trackInfo.setUserId(userId);
        trackInfo.setStatus(SystemConstant.TRACK_STATUS_PASS);// 状态：0501-审核通过

        // 1.1 处理声音的orderNum --- 这个声音的orderNum，需要从数据库中查询当前用户的最大orderNum，然后+1 第一张从1开始
        Integer orderNum = 1;
        // 当前声音下的所有声音 倒序取第一条
        TrackInfo trackInfoDesc = trackInfoMapper.selectOne(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, trackInfoVo.getAlbumId())
                .orderByDesc(TrackInfo::getOrderNum)
                .last("limit 1"));
        if (trackInfoDesc != null) {
            orderNum = trackInfoDesc.getOrderNum() + 1;
        }
        trackInfo.setOrderNum(orderNum);

        // 1.2 处理声音的媒体信息

        TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfoVo.getMediaFileId());

        if (trackMediaInfoVo == null) {
            log.error("媒体信息获取失败");
            throw new GuiguException(201, "媒体信息不存在");
        }
        trackInfo.setMediaSize(trackMediaInfoVo.getSize());
        trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
        trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
        trackInfo.setMediaType(trackMediaInfoVo.getType());

        trackInfoMapper.insert(trackInfo);
        // 2. 保存声音到track_stat
        Integer i = self.saveTrackStat(trackInfo.getId()); // 用代理对象调用 否则会出现事物失效 todo 此处使用AopContext时遇到问题(所有的Autowired都是null) 但自我注入没问题
        log.info("保存声音统计：{}", i == 1 ? "成功" : "失败");

        // 3. 添加对应专辑下的声音数量

        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfoVo.getAlbumId());
        if (albumInfo == null)
            throw new GuiguException(201, "专辑不存在");
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() + 1);
        int num = albumInfoMapper.updateById(albumInfo);
        log.info("增加专辑下声音数量：{}", num == 1 ? "成功" : "失败");

    }

    @Override
    public IPage<TrackListVo> findUserTrackPage(IPage<TrackListVo> page, TrackInfoQuery trackInfoQuery) {
        return trackInfoMapper.findUserTrackPage(page, trackInfoQuery);
    }

    @Override
    public TrackInfo getTrackInfo(Long trackId) {
        return trackInfoMapper.selectById(trackId);

    }

    @Override
    public void updateTrackInfo(TrackInfo trackInfo) {
        // 更新声音信息

        // 1. 判断一下声音是否改变
        TrackInfo trackInfoOld = trackInfoMapper.selectById(trackInfo.getId());
        if (trackInfoOld == null) {
            throw new GuiguException(201, "声音不存在");
        }
        // 2. 如果声音改变，更新声音的媒体信息
        if (!trackInfoOld.getMediaFileId().equals(trackInfo.getMediaFileId())) {
            TrackMediaInfoVo trackMediaInfoVo = vodService.getMediaInfo(trackInfo.getMediaFileId());
            trackInfo.setMediaSize(trackMediaInfoVo.getSize());
            trackInfo.setMediaDuration(BigDecimal.valueOf(trackMediaInfoVo.getDuration()));
            trackInfo.setMediaUrl(trackMediaInfoVo.getMediaUrl());
            trackInfo.setMediaType(trackMediaInfoVo.getType());
        }
        // 3. 没改 则直接更新声音信息
        int i = trackInfoMapper.updateById(trackInfo);
        log.info("更新声音信息：{}", i == 1 ? "成功" : "失败");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeTrackInfo(Long trackId) {
        // 删除声音
        // 先把要删的声音查出来 后面要用albumId 和 mediaFileId
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);

        // 1. 删除声音基本信息track_info
        int i = trackInfoMapper.deleteById(trackId);
        if (i > 0) {
            log.info("删除声音基本信息：{}", "成功");
        } else {
            throw new GuiguException(201, "声音不存在");
        }
        // 2. 删除声音统计信息track_stat
        int delete = trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>().eq(TrackStat::getTrackId, trackId));
        if (delete > 0) {
            log.info("删除声音统计：{}", "成功");
        } else {
            throw new GuiguException(201, "声音统计不存在");
        }
        // 3. 扣减专辑下声音数量
        // 3.1 查询专辑id

        // 3.2 查询专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(trackInfo.getAlbumId());
        if (albumInfo == null) {
            throw new GuiguException(201, "专辑不存在");
        }
        albumInfo.setIncludeTrackCount(albumInfo.getIncludeTrackCount() - 1);
        int num = albumInfoMapper.updateById(albumInfo);
        log.info("扣减专辑下声音数量：{}", num == 1 ? "成功" : "失败");
        // 4. 删除声音文件(删除云文件的文件)
        vodService.removeMediaFile(trackInfo.getMediaFileId());
        log.info("删除声音文件：{}", "成功");

    }

    @Override
    public IPage<AlbumTrackListVo> findAlbumTrackPage(IPage<AlbumTrackListVo> page, Long albumId) {
        IPage<AlbumTrackListVo> result = new Page<>();
        // 1. 查询专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "专辑不存在");
        }
        // 2. 查询专辑下的声音
        IPage<AlbumTrackListVo> albumTrackListVos = trackInfoMapper.findAlbumTrackPage(page, albumId);
        // "付费类型: 0101-免费、0102-vip免费、0103-付费"
        String payType = albumInfo.getPayType();
        // "价格类型： 0201-单集 0202-整专辑"
        String priceType = albumInfo.getPriceType();
        // 免费试听集数
        Integer tracksForFree = albumInfo.getTracksForFree();
        Long userId = AuthContextHolder.getUserId();
        // 根据用户id查询用户是否购买了该专辑 或声音 该用户是否是vip
        switch (payType) {
            case "0101":
                result = albumTrackListVos;
                break;
            case "0102":
                // 处理vip免费类型
                result = vipFreeAlbum(albumId, userId, priceType, tracksForFree, albumTrackListVos);
                break;
            case "0103":
                // 处理付费类型
                result = payAlbum(albumId, userId, priceType, tracksForFree, albumTrackListVos);
                break;
        }
        return result;
    }

    @Override
    public TrackStatVo getTrackStatVo(Long trackId) {
        return trackStatMapper.getTrackStatVo(trackId);
    }

    @Override
    public List<TrackListVo> getTrackListByIds(List<Long> trackIds) {
        List<TrackInfo> trackInfoList = trackInfoMapper.selectBatchIds(trackIds);
        return trackInfoList.stream().map(trackInfo -> {
            TrackListVo trackListVo = new TrackListVo();
            BeanUtils.copyProperties(trackInfo, trackListVo);
            trackListVo.setTrackId(trackInfo.getId());
            return trackListVo;
        }).toList();
    }

    @Override
    public List<Map<String, Object>> findUserTrackPaidList(Long trackId, Long userId) {
        List<Map<String, Object>> result = new ArrayList<>();
        // 1.先查询该声音的对象
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        Assert.notNull(trackInfo, "声音不存在");
        // 2.查询该专辑下后续的所有声音
        Long albumId = trackInfo.getAlbumId();
        // 3.获取该声音对应的专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        Assert.notNull(albumInfo, "该声音 " + trackId + " 下对应的专辑不存在");
        // 价格
        BigDecimal price = albumInfo.getPrice();
        // 4.查询当前声音的后续部分
        List<TrackInfo> trackInfoList = trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, albumId).gt(TrackInfo::getOrderNum, trackInfo.getOrderNum()).orderByAsc(TrackInfo::getOrderNum));
        // 5.将当前用户购买过的声音查询出来
        Result<Map<Long, String>> userPaidTrackInAlbumResult = userInfoFeignClient.getUserPaidTrackInAlbum(albumId, userId);
        Map<Long, String> trackPaidInfoMap = userPaidTrackInAlbumResult.getData();
        // 6.过滤掉用户已经购买的声音
        List<TrackInfo> trackShowList = trackInfoList.stream().filter(track -> !trackPaidInfoMap.containsKey(track.getId())).collect(Collectors.toList());
        // 7.每十集装到一个map里然后添加到list中 依次是后10集 后20集 后30集...若不足则显示所有的
        HashMap<String, Object> map = new HashMap<>();
        map.put("name", "本集");
        map.put("price", price);
        map.put("trackCount", 0);// 0 表示本集
        result.add(map);
        int totalNum = trackShowList.size();
        int loopTimes = totalNum % 10 == 0 ? totalNum / 10 : totalNum / 10 + 1;
        for (int i = 1; i <= loopTimes; i++) {
            if (i * 10 > totalNum) {
                Map<String, Object> map1 = new HashMap<>();
                map1.put("name", "后" + totalNum + "集");
                map1.put("price", price.multiply(new BigDecimal(totalNum)));
                map1.put("trackCount", totalNum);
                result.add(map1);
                break;
            }
            Map<String, Object> map1 = new HashMap<>();
            map1.put("name", "后" + i * 10 + "集");
            map1.put("price", price.multiply(new BigDecimal(i * 10)));
            map1.put("trackCount", i * 10);
            result.add(map1);
        }
        return result;
    }

    @Override
    public List<TrackInfo> getTrackListByCurrentTrackId(Long userId, Long trackId, Integer trackCount) {
        List<TrackInfo> result = new ArrayList<>();
        TrackInfo trackInfo = trackInfoMapper.selectById(trackId);
        if (trackInfo == null) {
            throw new GuiguException(201, "声音不存在");
        }
        // 查询该声音对应的专辑
        Long albumId = trackInfo.getAlbumId();
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        if (albumInfo == null) {
            throw new GuiguException(201, "该声音对应的专辑不存在");
        }
        // 判断当前买的是本集还是其他集
        if (trackCount == 0) {
            // 本集
            result.add(trackInfo);
        }else {
            // 其他集
            result = trackInfoMapper.selectList(new LambdaQueryWrapper<TrackInfo>().eq(TrackInfo::getAlbumId, albumId).gt(TrackInfo::getOrderNum, trackInfo.getOrderNum()).orderByAsc(TrackInfo::getOrderNum).last("limit " + trackCount));
        }
        return result;
    }

    @Override
    public Long getAlbumIdByTrackId(Long trackId) {
        return trackInfoMapper.selectById(trackId).getAlbumId();
    }

    /**
     * 处理付费类型 是否展示付费标签
     *
     * @param albumId
     * @param userId
     * @param priceType
     * @param tracksForFree
     * @return
     */
    private IPage<AlbumTrackListVo> payAlbum(Long albumId, Long userId, String priceType, Integer tracksForFree, IPage<AlbumTrackListVo> albumTrackListVos) {
        if (userId == null) {
            // 默认前五集免费 用户未登录 只显示五集免费的声音
            List<AlbumTrackListVo> list = albumTrackListVos.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() <= tracksForFree).toList();
            return albumTrackListVos.setRecords(list);
        }
        // 用户登录 查询用户是否购买了该专辑 或声音
        return getAlbumTrackListVoIPage(albumId, userId, priceType, tracksForFree, albumTrackListVos);
    }

    /**
     * 处理vip免费类型 是否展示付费标签
     *
     * @param albumId
     * @param userId
     * @param priceType
     * @param tracksForFree
     * @param albumTrackListVos
     * @return
     */
    private IPage<AlbumTrackListVo> vipFreeAlbum(Long albumId, Long userId, String priceType, Integer tracksForFree, IPage<AlbumTrackListVo> albumTrackListVos) {
        if (userId == null) {
            // 默认前五集免费 用户未登录 只显示五集免费的声音
            List<AlbumTrackListVo> list = albumTrackListVos.getRecords().stream().filter(albumTrackListVo -> albumTrackListVo.getOrderNum() <= tracksForFree).toList();
            return albumTrackListVos.setRecords(list);
        }
        // 用户登录 查询用户是否购买了该专辑 或声音 该用户是否是vip
        // 先判断用户是否是vip 如果是 判断是否过期
        Result<UserInfoVo> userInfoVoResult = userInfoFeignClient.getUserInfo(userId);
        UserInfoVo userInfoVo = userInfoVoResult.getData();
        if (userInfoVo == null) {
            throw new GuiguException(201, "用户信息不存在");
        }
        Integer isVip = userInfoVo.getIsVip();// 0-普通用户 1-VIP用户
        Date vipExpireTime = userInfoVo.getVipExpireTime();
        if (isVip == 1 && vipExpireTime.after(new Date())) {
            return albumTrackListVos;
        } else return getAlbumTrackListVoIPage(albumId, userId, priceType, tracksForFree, albumTrackListVos);

    }

    /**
     * 处理用户购买了该专辑 或声音
     *
     * @param albumId
     * @param userId
     * @param priceType
     * @param tracksForFree
     * @param albumTrackListVos
     * @return
     */
    private IPage<AlbumTrackListVo> getAlbumTrackListVoIPage(Long albumId, Long userId, String priceType, Integer tracksForFree, IPage<AlbumTrackListVo> albumTrackListVos) {
        // 默认前五集免费 再看用户有没有买过该专辑 或 声音
        // 先看价格类型 0201-单集 0202-整专辑
        if ("0201".equals(priceType)) {
            // 单集付费
            // 查询用户购买了该专辑下的哪些声音
            Result<Map<Long, String>> userPaidTrackInAlbumMap = userInfoFeignClient.getUserPaidTrackInAlbum(albumId, userId);
            Map<Long, String> userPaidTrackInAlbumMapData = userPaidTrackInAlbumMap.getData();
            if (userPaidTrackInAlbumMapData == null)
                throw new GuiguException(201, "远程查询用户微服务获取用户购买声音信息失败");
            List<AlbumTrackListVo> list = albumTrackListVos.getRecords().stream().map(albumTrackListVo -> {
                if (albumTrackListVo.getOrderNum() <= tracksForFree) {
                    albumTrackListVo.setIsShowPaidMark(false);
                } else {
                    // true -> 显示付费标识
                    albumTrackListVo.setIsShowPaidMark(!userPaidTrackInAlbumMapData.containsKey(albumTrackListVo.getTrackId()));
                }
                return albumTrackListVo;
            }).toList();
            return albumTrackListVos.setRecords(list);
        } else {
            // 整专辑付费
            // 查询用户有没有购买该专辑记录
            Result<Boolean> userInfoFeignClientUserPaidAlbumByIdResult = userInfoFeignClient.getUserPaidAlbumById(albumId, userId);
            Boolean userPaidAlbumByIdData = userInfoFeignClientUserPaidAlbumByIdResult.getData();
            if (userPaidAlbumByIdData == null)
                throw new GuiguException(201, "远程查询用户微服务获取用户购买专辑信息失败");
            if (userPaidAlbumByIdData) {
                return albumTrackListVos;
            } else {
                // 前五集显示免费 后面都是付费
                List<AlbumTrackListVo> list = albumTrackListVos.getRecords().stream().map(albumTrackListVo -> {
                    if (albumTrackListVo.getOrderNum() <= tracksForFree) {
                        albumTrackListVo.setIsShowPaidMark(false);
                    } else {
                        // true -> 显示付费标识
                        albumTrackListVo.setIsShowPaidMark(true);
                    }
                    return albumTrackListVo;
                }).toList();
                return albumTrackListVos.setRecords(list);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Integer saveTrackStat(Long id) {
        try {
            ArrayList<String> trackStatus = new ArrayList<>(); // 播放量，订阅量，点赞量，评论量
            trackStatus.add(SystemConstant.TRACK_STAT_PLAY);
            trackStatus.add(SystemConstant.TRACK_STAT_COLLECT);
            trackStatus.add(SystemConstant.TRACK_STAT_PRAISE);
            trackStatus.add(SystemConstant.TRACK_STAT_COMMENT);
            trackStatus.forEach(statType -> {
                TrackStat trackStat = new TrackStat();
                trackStat.setTrackId(id);
                trackStat.setStatType(statType);
                trackStat.setStatNum(0);
                trackStatMapper.insert(trackStat);
            });
            return 1;
        } catch (Exception e) {
            return 0;
        }
    }
}
